﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;

using System.IO;
using System.Xml;
using System.Xml.Serialization;

#endregion

namespace Weazel.Toad.Application.Items
{
  [Serializable]
  public class Project : ItemBase
  {
    #region Project events

    public static event EventHandler<EventArgs> ProjectCreated;
    public static event EventHandler<EventArgs> ProjectOpened;
    public static event EventHandler<CancelEventArgs> ProjectClosing;
    public static event EventHandler<EventArgs> ProjectClosed;
    
    #endregion

    private EventHandler<ItemOpenedOrClosedEventArgs> itemOpenedEventHandler;
    public EventHandler<ItemOpenedOrClosedEventArgs> ItemOpenedEventHandler
    {
      get { return itemOpenedEventHandler; }
    }

    private static XmlSerializer serializer;

    private List<ItemBase> items;

    public List<ItemBase> Items
    {
      get { return items; }
      set { items = value; }
    }

    public override string FileTypeName
    {
      get { return "Project"; }
    }

    public override string Extension
    {
      get { return "xprj"; }
    }

    /// <summary>
    /// Must have default constructor
    /// in order to be serializable. Do
    /// not call - use CreateProject instead.
    /// </summary>
    public Project()
    {
      this.items = new List<ItemBase>();
      this.DisplayName = "unnamed.xprj";

      this.itemOpenedEventHandler = new EventHandler<ItemOpenedOrClosedEventArgs>(HandleItemOpenedEvent);
    }

    /// <summary>
    /// This handler is called whenever an item is opened in the application
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    public void HandleItemOpenedEvent(object sender, ItemOpenedOrClosedEventArgs args)
    {
      AddItem(args.Item);
    }

    public virtual void AddItem(ItemBase item)
    {
      if (!items.Contains(item))
      {
        items.Add(item);
        OnItemChanged();
      }
    }

    public virtual void RemoveItem(ItemBase item)
    {
      if (items.Contains(item))
      {
        items.Remove(item);
        OnItemChanged();        
      }
    }

    #region project create, open and close operations

    public static bool CreateProject(string filename, string displayname)
    {
      Project currentProject = Application.Instance.Project;

      if (currentProject != null)
      {
        bool closed = CloseProject();

        // closing current project cancelled
        // thus cancel new project operation
        if (!closed)
          return false;
      }

      Project project = new Project();
      project.Filename = filename;
      project.DisplayName = displayname;

      Application.Instance.Project = project;

      if (ProjectCreated != null)
      {
        ProjectCreated(project, EventArgs.Empty);
      }

      if (filename != null)
        project.Save();
      else
        project.SaveAs();

      return true;
    }

    public static bool CreateProject()
    {
      return CreateProject(null, null);
    }

    public static bool OpenProject()
    {
      OpenFileDialog openDialog = new OpenFileDialog();
      openDialog.Title = "Open Project";
      openDialog.AddExtension = true;
      openDialog.DefaultExt = ".xprj";
      openDialog.CheckFileExists = true;
      openDialog.Multiselect = false;
      openDialog.Filter = string.Format("{0} Files (*.{1})|*.{1}", "Project", "xprj");

      if (openDialog.ShowDialog() == DialogResult.OK)
      {
        return OpenProject(openDialog.FileName);
      }

      return false;
    }

    public static bool OpenProject(string filename)
    {
      Project currentProject = Application.Instance.Project;

      if (currentProject != null)
      {
        bool closed = CloseProject();
        // closing current project cancelled
        // thus cancel open operation
        if (!closed)
          return false;
      }

      Project project = null;

      using (StreamReader writer = new StreamReader(filename))
      {
        if (serializer == null)
          InitializeSerializer();

        project = (Project)serializer.Deserialize(writer);
        
        if (ProjectOpened != null)
        {
          ProjectOpened(project, EventArgs.Empty);
        }
      }

      Application.Instance.Project = project;

      return true;
    }

    /// <summary>
    /// Returns true iff the project was closed
    /// or false if the close operation was cancelled.
    /// </summary>
    /// <param name="project"></param>
    /// <param name="save"></param>
    /// <returns></returns>
    public static bool CloseProject()
    {
      Project project = Application.Instance.Project;
      System.Diagnostics.Debug.Assert(project != null);

      if (ProjectClosing != null)
      {
        CancelEventArgs args = new CancelEventArgs();
        ProjectClosing(project, args);
        // close operation cancelled, return false
        if (args.Cancel)
          return false;
      }

      Application.Instance.Project = null;

      if (ProjectClosed != null)
      {
        ProjectClosed(project, EventArgs.Empty);
      }

      return true;
    }

    #endregion

    #region persistence operations

    protected override void SaveInternal()
    {
      // if first time called
      // initialize serializer
      if (serializer == null)
        InitializeSerializer();

      using (StreamWriter writer = new StreamWriter(Filename))
      {
        serializer.Serialize(writer, this);
      }
    }

    private static void InitializeSerializer()
    {
      serializer = new XmlSerializer(typeof(Project));
    }

    #endregion
  }
}
